# Python 函数

# 函数是组织好的，可重复使用的，用来实现单一，或相关联功能的代码段。
# 函数能提高应用的模块性，和代码的重复利用率。Python提供了许多内建函数，比如print()。
# 但你也可以自己创建函数，这被叫做用户自定义函数


# 定义函数语法
# def 函数名(参数列表):
#     函数体
#     return 返回值
# return 语句是可选的，如果函数没有 return 语句，则默认返回 None。


# 定义一个简单的函数
def say_hello():
    print("Hello, world!")
# 调用函数
say_hello()


# 带参数的函数
def greet(name):
    print("Hello, " + name + "!")
# 调用带参数的函数
greet("Alice")
greet("Bob")


# 带默认参数的函数
def greet_with_default(name="world"):
    print("Hello, " + name + "!")
# 调用带默认参数的函数
greet_with_default()
greet_with_default("Alice")


# 带可变参数的函数，以元组形式导入参数
def sum_numbers(*numbers):
    result = 0
    for num in numbers:
        result += num
    return result
# 调用带可变参数的函数
print(sum_numbers(1, 2, 3))
print(sum_numbers(4, 5, 6, 7, 8))


# 不指定顺序传参
def print_info(name, age):
    print("姓名:", name)
    print("年龄:", age)
# 调用不指定顺序传参的函数
print_info(age=20, name="风清影竹")


# 带**号传参的函数, 加了两个星号 ** 的参数会以字典的形式导入
def print_info_with_dict(**info):
    print("姓名:", info["name"])
    print("年龄:", info["age"])
# 调用带**号传参的函数
print_info_with_dict(name="风清影竹", age=20)


# 不可变对象作为参数(整数，字符串，元组)
# 函数内部修改不可变对象，不会影响到原数据，相当于函数对不可变对象进行了浅拷贝。
def modify_num(n):
    n +=10
    print("函数内部修改后的 num:", n)
num = 10
modify_num(num)
print("函数外部的 num:", num)


# 可变对象作为参数(列表，字典)
# 函数内部修改可变对象，会影响到原数据，相当于函数对可变对象进行了深拷贝。
def modify_list(lst):
    lst.append(10)
    print("函数内部修改后的 lst:", lst)
lst = [1, 2, 3]
modify_list(lst)
print("函数外部的 lst:", lst)


# 有返回值的函数
def add(x, y):
    """    这是一个加法函数   """
    return x + y
# 调用有返回值的函数
print("和为:", add(1, 2))


# 返回多个值的函数
def get_info(name, age):
    return name, age
# 调用返回多个值的函数
name, age = get_info("风清影竹", 20)
print("姓名:", name)
print("年龄:", age)


# 返回None的函数
def print_none():
    pass    # 空语句，没有任何功能，但返回 None
# 调用返回None的函数
print("无return语句的函数返回值:", print_none())


# 成绩分析函，返回一组成绩的最高分和平均分
def analyze_scores(*scores):
    highest = max(scores)
    average = sum(scores) / len(scores)
    return highest, average
# 调用成绩分析函
scores = [80, 90, 70, 60]
highest, average = analyze_scores(*scores)
print("最高分:", highest)
print("平均分:", average)


# 元组/列表传参自动解包(*)
# 传参自动解包是指，在函数调用时，Python会自动将元组或列表等可迭代对象中的元素作为参数传入。
def add(a, b, c):
    return a + b + c
# 调用传参自动解包
params = [1, 2, 3]
print("自动解包后结果:", add(*params))     # *params 自动解包为 1, 2, 3


# 字典传参自动解包(**)
def greet(name, msg):
    print(f"{name},{msg}")
params = {"name": "风清影竹", "msg": "Python大神!"}
# 调用字典传参自动解包
greet(**params)     # **params 自动解包为 name="风清影竹", msg="Python大神!"


# 常见错误
# 位置参数在关键字参数之后
# func(a = 1, b)  # 错误，位置参数在关键字参数之后


# 复杂参数类型
# 位置参数：a, b, c
# 可变参数(元组/列表)：*args
# 关键字参数(字典)：**kwargs
def complex_func(a, b, c, *args, **kwargs):
    print(a, b, c, args, kwargs, sep="\n")
# 调用复杂参数类型
complex_func(1, 2, 3, 4, 5, 6, name="风清影竹", age=20)


# 动态生成SQL案例
def generate_sql(table_name, **conditions):
    sql = "SELECT * FROM " + table_name
    if conditions:
        sql += " WHERE "
        for key, value in conditions.items():
            sql += key + " = '" + str(value) + "' AND "
        sql = sql[:-4]   # 去掉最后的 AND
    return sql
# 调用动态生成SQL案例
sql = generate_sql("users", name="风清影竹", age=20)
print(sql)


# 递归函数
def factorial(n):
    return 1 if n == 0 else n * factorial(n - 1)
# 调用递归函数
print("递归结果:", factorial(5))

